Синтаксис языка Julia
Переменные и типы данных
Переменные
Переменная в Julia – это имя, связанное со значением. Ее целесообразно применять, когда вы хотите сохранить значение (полученное, например, после математических вычислений) для последующего использования.
Например, присвоим переменной x значение 10. Это делается с помощью оператора присваивания =.
x = 10
Для добавления текстового комментария служит символ # (решетка). Весь текст после # и до конца строки будет рассматриваться не как часть кода, а как комментарий. Например:
x = 10 # Присвоим переменной x значение 10
Если в строке кода набрать просто имя переменной, то после выполнения строки на экран будет выведено значение этой переменной (конечно, если переменной ранее было присвоено какое-нибудь значение).
x
Переменную x можно использовать в дальнейших вычислениях:
z = x + 5
Переменной x можно присваивать новые значения. Например, или "Hello":
x = sqrt(2)
x = "Hello"
Язык Julia чувствителен к регистру, т.е. переменные с именами a и A являются разными, функции с названиями Func и func тоже различны.
Текст в Julia вводится с использованием кодировки UTF-8. В кодировке UTF-8 символы могут быть представлены разным количеством байтов.
Разрешенные имена переменных
Имена переменных должны начинаться с буквы (A – Z или a – z), цифры, знака подчеркивания (_) или подмножества кодов символов Unicode больше 00A0. Последующие символы могут также включать !, цифры и другие символы. Таким образом, в именах переменных могут присутствовать буквы кириллицы, греческие буквы, различные математические символы и т.д.
Примеры:
Радиус = 100
φ = 1.75
В именах переменных нельзя использовать пробелы.
Запрещенными именами для переменных являются имена встроенных ключевых слов.
Ниже приведен список зарезервированных ключевых слов в Julia: baremodule, begin, break, catch, const, continue, do, else, elseif, end, export, false, finally, for, function, global, if, import, let, local, macro, module, quote, return, struct, true, try, using, while. Их запрещено использовать в качестве имен переменных.
Также зарезервированы следующие последовательности из двух слов: abstract type, mutable struct, primitive type. Однако можно создавать переменные с именами abstract, mutable, primitive и type.
Больше об именах переменных вы можете прочитать в документации.
Типы данных
Каждая величина обязательно имеет какой-то тип, но связан он не с именами переменных (как это характерно для предварительно компилируемых языков вроде C/C++), а с самими величинами, поэтому переменная не требует обязательного объявления типа: он станет известен после присваивания ей величины.
Типы данных в Julia образуют стройную древовидную иерархию. Самый верхний (общий) тип – Any. Все остальные типы являются его подтипами (субтипами). Тип Number (число) является подтипом Any. В свою очередь, Number является супертипом для Real и Complex. Иерархия подтипов Number в Julia приведена на рисунке.

Целые числа – Integer
Целый тип Integer – это подтип вещественного типа Real. В свою очередь, подтипами Integer являются Int8,
Int16, Int32, Int64, Int128 (со знаком) и UInt8, UInt16, UInt32, UInt64, UInt128 (без знака). Здесь 8, 16, 32, 64, 128 – число бит, которое занимает переменная в памяти.
Наименьшее и наибольшее значения, которые может принять переменная, можно получить с помощью функций typemin() и typemax() соответственно.
Предельные параметры целочисленных типов Julia демонстрирует следующий пример:
for T in [Int8,Int16,Int32,Int64,Int128,UInt8,UInt16,UInt32,UInt64,UInt128]
println("$(lpad(T,7)): [$(typemin(T)),$(typemax(T))]")
end
В результате выполнения этого кода будут выведены следующие данные:
Int8: [-128,127]
Int16: [-32768,32767]
Int32: [-2147483648,2147483647]
Int64: [-9223372036854775808,9223372036854775807]
Int128: [-170141183460469231731687303715884105728,170141183460469231731687303715884105727]
UInt8: [0,255]
UInt16: [0,65535]
UInt32: [0,4294967295]
UInt64: [0,18446744073709551615]
UInt128: [0,340282366920938463463374607431768211455]
Примеры задания переменных целого типа:
a = 100
b = -232143284
Логические переменные – Bool
Логический тип является подтипом Integer. Логические переменные типа Bool также являются 8-битными целыми числами. Значение true (истина) соответствует 1, значение false (ложь) соответствует 0.
Например:
a = true
b = false
c = 1 > 2
d = 1 < 2
Переменная c принимает значение false, т.к. логическое выражение 1 > 2 ложное. А переменная d принимает значение true, т.к логическое выражение 1 < 2 истинное. Подробнее о логических выражениях мы поговорим во второй части.
Вещественные числа
Вещественнный тип AbstractFloat содержит следующие типы: Float16, Float32 и Float64. Число в названии типа показывает количество байтов, занимаемых в памяти на хранение переменной. Например:
a = 1.0
b = -12.75
Можно использовать экспоненциальную нотацию. Число вводится так:
x = 1.6e-19
По умолчанию приведенные выше вещественные числа имеют тип Float64. Если вместо e ввести f, то получится число в формате Float32:
x = 1.6f-19
Число задается с помощью зарезервированной константы pi:
x = pi
Комплексные числа – Complex
Глобальная константа im обозначает мнимую единицу (главное значение квадратного корня из ). Комплексные числа записываются в виде a+b im, где a и b – вещественные числа. Например: 3+2im, -1-5im и т.д. Обратите внимание, что знак умножения * между мнимой частью и константой im можно не писать.
Примеры выполнения арифметических операций с комплексными числами:
(5 + 3im)*(4 - 2im)
(8 + 7im)/(3 - 4im)
(-9 + 1im) - (2 - 5im)
(3+7im)^3
(1+1im)^(1+1im)
Для работы с комплексными числами существуют следуюшие функции:
real(z)– вычисление вещественной части;imag(z)– вычисление мнимой части числа;reim(z)– вычисление вещественной и мнимой части в виде кортежа;conj(z)– комплексное сопряжение числа;abs(z)– вычисление модуля;abs2(z)– вычисление квадрата модуля;angle(z)– вычисление аргумента.
Примеры:
z = 2+3im
real(z)
imag(z)
reim(z)
conj(z)
abs(z)
abs2(z)
angle(z)
Для комплексных чисел также определны все элементарные функции. Например, мы можем вычислить и :
exp(z)
sin(z)
Если результат выполнения действия над вещественным числом принимает комплексное значение, то это вещественное число нужно предварительно преобразовать в комплексный тип с помощью функции complex.
Например, извлечение квадратного корня из отрицательного числа выполнятеся так:
sqrt(complex(-2))
А вот пример вычисления натурального логарифма от отрицательного числа:
log(complex(-1))
Если аргументы этих функций не преобразовать в комплексный вид, то возникнет ошибка:
sqrt(-2)
DomainError with -2.0:
sqrt will only return a complex result if called with a complex argument. Try sqrt(Complex(x)).
log(-1)
DomainError with -1.0:
log will only return a complex result if called with a complex argument. Try log(Complex(x)).
Функцию complex также можно использовать для формирования комплексного числа напрямую из его вещественной и мнимой частей:
complex(4,5)
Рациональные числа – Rational
В Julia реализована интересная возможность – вычисления с рациональными числами. Рациональные числа записываются в виде дроби вида a//b, где a и b – целые числа.
Например, рациональная дробь записывается следующим образом:
4//9
При сложении и вычитании рациональных чисел они приводятся к общему знаменателю, их числители складываются (вычитаются) и затем, если это возможно, выполняется сокращение дроби. Например:
1//3 + 1//7
Преобразовать рациональное число в вещественный тип можно с помощью функции float:
a = 3//8
float(a)
Символы – Char
Переменные символьного типа Char задаются следующим образом:
c = 'A'
Строки – String
Строка в Julia – это упорядоченный набор символов. Строки заключаются в двойные кавычки " " или в тройные двойные кавычки """ """.
Пример:
s = "Hello, world!"
Подробнее о символьном и строковом типах данных мы поговорим далее в этой части.
Векторы – Array
Массивы (упорядоченные множества объектов одного типа) в Julia могут быть заданы как в виде векторов (Array), так и в виде матриц (Matrix).
Вектор (одномерный массив) задается перечислением его элементов через запятую или точку с запятой в квадратных скобках. Например:
a = [1, 2, 3, 4, 5]
a = [1; 2; 3; 4; 5]
Матрицы – Matrix
Матрица-строка (одномерный массив) создается с помощью перечисления ее элементов через пробел в квадратных скобках. Например:
a = [1 2 3 4 5]
Если матрица содержит несколько строк (двумерный массив), то она задается аналогично. Ввод элементов осуществляется по строкам, строки отделяются друг от друга точкой с запятой. Например:
a = [1 2 3 4 5; 6 7 8 9 10; 11 12 13 14 15]
Разумеется, элементами векторов и матриц могут служить не только целые числа, как в приведенных примерах, но и элементы любого другого типа (вещественные, комплексные, рациональные числа, символы, строки и даже другие векторы и матрицы).
Кортежи – Tuple
Кортеж (Tuple) – группа значений некоторых величин фиксированной длины, разделенных запятыми, иногда эту группу окружают круглыми скобками. Кортеж может содержать данные разных типов, в отличие от массива, в котором содержатся данные одного типа.
Пример:
c = (1, 1.1, pi, 'c', "Julia", 1//3)
Кортеж можно превратить в вектор типа Any: v=[c…].
Вектор можно превратить в кортеж: c=(v…,).
Элементы кортежа изменять нельзя, в отличие от элементов массива. Выражение c[1] = 2 вызовет сообщение об ошибке.
Можно использовать именованный кортеж вида c = (a=1, b=2.2). Доступ к
элементам кортежа возможен либо через индекс, например, c[1], либо по имени c.a, c.b.
Если список возвращаемых величин какой-либо функции содержит несколько значений, то возвращаются они в форме кортежа или массива (когда возвращается массив данных).
Множества – Set
Множества (в отличие от массивов) используются для хранения коллекций неупорядоченных уникальных значений. Множество в Julia создается с помощью команды Set. В качестве аргумента в квадратных скобках записывается массив (вектор или матрица) элементов, из которых должно состоять множество.
Пример. Создадим множество, состоящее из элементов 1, 3, 5 и 7:
s = Set([1, 3, 5, 7])
Добавление элемента к множеству производится с использованием оператора push!.
Пример. Добавим в множество s элемент 2:
push!(s, 2)
Другие функции для работы с множествами:
intersect(set1,set2)– пересечение;union(set1,set2)– объединение;setdiff(set1,set2)– разность.
Превратить строку st в множество содержащихся в ней символов можно так: x = Set(st).
Аналогичным образом в множество можно превратить массив z (одномерный
или многомерный): x = Set(z).
Словари – Dict
Словарь (Dict) – это ассоциативный массив, состоящий из пар ключ – значение. Cловарь создается с помощью оператора Dict.
Примеры задания словаря:
d = Dict('a'=>1, 'b'=>2, 'c'=>3)
d = Dict([('a', 1), ('b', 2), ('c', 3)])
Здесь 'a', 'b' и 'c' – имена ключей. В данном примере они заданы переменными символьного типа. А 1, 2 и 3 – значения этих ключей. Имена ключей могут быть символами или строками.
Константы
Поскольку тип переменных в Julia легко изменяется, это приводит к дополнительной нагрузке на ресурсы компьютера. Чтобы уменьшить эту нагрузку, можно использовать определение переменной с использованием ключевого слова const:
const o = 10.0
const l = [1 2 3]
Значения переменных, объявленных таким образом, можно изменять, однако их тип менять нельзя, т.е. o = 5.0 допустимо, а o = [1 2 3] – нет.
Определение типа величины
Определить тип какой-либо величины можно, вызывая для нее функцию typeof().
Примеры:
typeof(10)
typeof(3.14)
typeof("name")
typeof([1; 2; 3])
typeof(true)
Преобразование типов
Запись T(x) или convert(T,x) преобразует величину x в значение типа T.
Примеры преобразования вещественного типа в целый (команда Int равносильна преобразованию значения в тип Int64):
Int(127.0)
convert(Int, 127.0)
Если дробная часть вещественнного числа отлична от нуля, то при попытке его преобразования в целый тип возникнет ошибка. Например:
Int(3.14)
ERROR: InexactError: Int64(3.14)
Stacktrace:
[1] Int64(x::Float64)
@ Base ./float.jl:900
[2] top-level scope
@ In[29]:1
Рассмотрим еще несколько примеров.
Преобразование логического типа в целый:
Int(true)
Преобразование логического типа в вещественный (команда float равносильна преобразованию значения в тип Float64):
float(false)
Преобразование целого типа в вещественный:
float(100)
Преобразование рационального типа в вещественный:
float(137//693)
Преобразование целого типа в комплексный:
Complex(2)
Преобразование вещественного типа в комплексный:
Complex(25.1)
Преобразование целого типа в строковый:
string(100)
Преобразование вещественного типа в строковый:
string(123.45)
Преобразование символьного типа в строковый:
string('A')
Чтобы преобразовать переменную строкового типа x в числовой тип T (целый, вещественный), используется функция parse:
parse(T, x)
Пример. Преобразуем строку в целый тип:
parse(Int, "123")
Преобразуем строку в вещественный тип (здесь нужно указывать конкретный тип вещественных чисел: Float16, Float32 или Float64):
parse(Float64, "123.45")
Особые значения с плавающей запятой
Существует три определенных стандартных значения с плавающей запятой, которые не соответствуют ни одной точке на прямой вещественных чисел:
Inf– положительная бесконечность. Значение, большее чем все конечные значения с плавающей запятой.-Inf– отрицательная бесконечность. Значение, меньшее чем все конечные значения с плавающей запятой.NaN(Not a Number) – не число. Значение, не равное никакому значению с плавающей запятой (включая его само).
Эти значения являются результатами определенных арифметических операций:
1/0
-5/0
1/Inf
1/-Inf
0/0
Inf - Inf
0 * Inf
Выражения
Оператор присваивания
Оператор присваивания в Julia имеет вид =.
Пример. Чтобы присвоить переменной a значение 1, нужно выполнить следующий код:
a = 1
Можно с помощью цепочки равенств присвоить значение 2 сразу двум переменным a и b:
a = b = 2
Арифметические операторы
+x– унарный плюс (операция тождественности);-x– унарный минус (изменение знакаxна противоположный);x + y– сложение;x - y– вычитание;x * y– умножение;x / y– деление;x ÷ y– целочисленное деление (с округлением до целого числа);x \ y– деление с инверсией (эквивалентноy / x);x ^ y– возведение в степень (xв степениy);x % y– остаток от деленияxнаy;sqrt(x)– квадратный корень изx.
Приоритет действий стандартный: сначала выполняются унарные операции, затем возведение в степень, затем *, /, ÷, \, % и, наконец, сложение и вычитание.
Помещение числового множителя непосредственно перед переменной или скобками, например 2x или 2(x+y), рассматривается как умножение, причем с большим приоритетом, чем у других двоичных операций.
Операторы, выполняемые раньше других близлежащих операторов, отделяются меньшим расстоянием. Например, запись -x + 2 означает, что сначала выполняется инверсия x, а затем к результату прибавляется число 2.
Несколько простых примеров использования арифметических операторов:
543.6 + 987.6 + 321.2
1 - 2 + 3 - 4 + 5
3 * 2 / 12
100 ÷ 17
12 \ 3
pi^3
25 % 4
sqrt(1000)
Если необходимо изменить порядок действий, то используются круглые скобки (). В математическом выражении может быть сколько угодно вложенных друг в друга пар круглых скобок.
Пример. Вычислим значение выражения . Для этого и основание, и показатель степени нужно взять в скобки:
(3.1+5.2*9.3)^(1+4/7)
Составные операторы
Иногда бывает удобно использовать выражение, в котором несколько подвыражений вычисляются по порядку и которое возвращает результат последнего подвыражения. Для этого в Julia есть две конструкции: блоки begin – end и цепочки через ;. Значением обеих конструкций составных выражений является результат последнего подвыражения.
Вот пример блока begin – end:
z = begin
x = 5
y = 10
x * y
end
Так как эти выражения достаточно простые, их можно легко записать в одну строку, и здесь будет удобен синтаксис цепочки через ;:
z = (x = 5; y = 10; x * y)
Такой синтаксис особенно полезен для сжатых однострочных определений функций.
Обычно блоки begin – end многострочные, а цепочки через ; – однострочные, но это не строгое требование:
z = begin x = 5; y = 10; x * y end
z = (x = 5;
y = 10;
x * y)
Логические операторы
Для типа Bool поддерживаются следующие логические операторы:
!x– отрицание (НЕ). Изменяетtrueнаfalseи наоборот;x && y– логическое умножение (конъюнкция, И);x || y– логическое сложение (дизъюнкция, ИЛИ).
Bool представляет собой целочисленный тип, и для него также определяются все арифметические операторы и операторы сравнения.
Битовые операторы
Для всех примитивных целочисленных типов поддерживаются следующие битовые операторы:
~x– битовое НЕ;x & y– битовое И;x | y– битовое ИЛИ;xor(x,y)илиx ⊻ y– битовое исключающее ИЛИ;- 'x ⊼ y' – битовое И НЕ;
x ⊽ y– битовое ИЛИ НЕ;x >>> y– логический сдвиг вправо;x >> y– арифметический сдвиг вправо;x << y– логический/арифметический сдвиг влево.
Примеры использования битовых операторов:
~253
253 & 342
253 | 342
xor(253,342)
253 ⊻ 342
253 ⊼ 342
253 ⊽ 342
Все двоичные арифметические и битовые операторы имеют версию с присваиванием, которая передает результат операнду, стоящему слева. Для использования версии двоичного оператора с присваиванием необходимо сразу после оператора указать знак =. Оператор с присваиванием переопределяет значение переменной в левой части. Например, запись x += 3 эквивалентна записи x = x + 3.
Пример. Сначала присвоим переменной x значение 1, затем прибавим к нему 3 и результат сохраним в той же переменной x.
x = 1
x += 3
Все версии двоичных арифметических и битовых операторов с присваиванием:
+= -= *= /= \= ÷= %= ^= &= |= ⊻= >>>= >>= <<=
Векторные операторы с точкой
Для каждой двоичной операции (+, -, *, /, ^ и т.д.), имеется соответствующая операция с точкой, т.е. .+, .-, .*, ./, .^ и т.д. В этом случае операции выполняются поэлементно для каждого значения массива. Например, операция [1, 2, 3] ^ 3 не определена, т.к. не существует стандартной математической операции возведения в куб для неквадратного массива. Однако определена операция
[1, 2, 3] .^ 3
Эта операция поэлементно вычисляет векторный результат [1^3, 2^3, 3^3].
Операции с точкой позволяют сочетать массивы со скалярными значениями, сочетать друг с другом массивы одинакового размера и даже массивы разных размеров (например, сочетать горизонтальные и вертикальные векторы, создавая матрицу).
При сочетании точечных операторов с числовыми выражениями может возникать неоднозначность. Например, что означает 1.+x? Это может быть 1. + x или 1 .+ x. Поэтому такой синтаксис не разрешен; в таких случаях нужно ставить вокруг оператора пробелы.
Операторы сравнения
Для всех примитивных числовых типов определены следующие операции сравнения:
==– равенство;!=,≠– неравенство;<– меньше;<=,≤– меньше или равно;>– больше;>=,≥– больше или равно.
Результат выполнения этих операций имет логический тип (true или false).
Несколько простых примеров использования операторов сравнения:
5 == 5
1 == 0
1 != 2
1<2
3>=3
10 < -10
Цепочки сравнений
В отличие от большинства языков, в Julia возможны произвольные цепочки сравнений.
Например:
1 < 2 < 3
Результат будет равен true, если результат всех сравнений в этой цепочке – истина, и false – в противном случае.
Чтение и запись данных
Вывод данных на экран
Самый простой способ вывести на экран значение переменной или математического выражения – это написать имя переменной или выражения без точки с запятой после них.
Пример. Если переменной x присвоить значение 1, то после выполнения такой строки кода на экран выведется значение переменной x:
x = 1
Т.к. переменная x уже определена, то, просто написав имя этой переменной, вы получите ее значение:
x
Точно так же на экран выводятся результаты выполнения математических действий:
2 + 3
2 > 1
Если после выражения поставить точку с запятой, то вывод на экран значения этого выражения будет заблокирован:
x = 2;
4*5;
Если в кодовой ячейке содержится несколько выражений, то после выполнения этой ячейки на экран будет выведен результат выполнения только последнего выражения. Например, после выполнения следующей ячейки будет выведено значение только переменой t:
x = 1
y = 2
z = 3; t = 4
Если вам нужно вывести данные на экран в произвольном месте кодовой ячейки, то это можно следать с помощью следующих функций:
print– вывод на экран значений переменных, констант, математических или логических выражений. Если нужно вывести несколько значений (x, y, z), то они перечисляются через запятую:print(x, y, z);println– то же, что иprint, но с переходом на новую строку, т.е. следующий вывод будет производиться в новой строке;display– то же, что иprint, но у этой функции может быть только один аргумент (константа, переменная или выражение).show– то же, что иdisplay.
Ниже приведены несколько примеров использования функции print:
print(2*3+5)
print(true)
print('A')
X = 10
print("X = ", X)
X = [11 12 13]
print("X = ", X)
print(1>2)
Ниже приведены несколько примеров использования функции display:
display("Hello, world!")
display(22/7)
Несколько примеров использования функции show:
show("This is my text")
a = 3.5
show(a)
Функция summary возвращает тип переменной. Для массивов возвращается также их размер.
Пример. Выведем на экран информацию о матрице x:
x = [1 2 3; 4 5 6]
summary(x)
Форматированный вывод
Вы можете управлять точностью отображения переменных с помощью функции @printf. Эта функция будет доступна, если подключить библиотеку Printf.
Пример. Выведем на экран значение переменной x = 12.67835675 с точностью до 4 знаков после запятой:
using Printf
x = 12.67835675
@printf("%.4f", x)
Выражение в кавычках "%.4f" задает формат вывода переменной: .4 означает число знаков после запятой, буква f задает тип данных, который имеет переменная x. В данном случае f – вещественный тип; также возможны i – целый тип, e – экспоненциальная запись, s – строковый тип и др. В качестве второго аргумента функции @printf указывается имя переменной x, значение которой нужно вывести на экран. Полную информацию о формате вывода с помощью функции @printf вы можете посмотреть в документации.
Ввод данных с клавиатуры
Ввести данные с клавиатуры можно с помощью функции readline(). Рассмотрим два случая:
- Если нужно ввести переменную
xстрокового типа, то используется следующая конструкция:
x = readline()
- Если нужно ввести переменную простого числового типа (целого, вещестенного или логического), то используется такая запись:
x = parse(Type, readline())
Функция readline предназначена для ввода данных только строкового типа. Чтобы преобразовать введенную переменную в числовой тип, используется функция parse. Ее первый аргумент Type задает тип переменной (Int, Float64, Float32, Bool и т.д.), в который нужно преобразовать строковую переменную, заданную вторым аргументомreadline().
Пример. Введем с клавиатуры значение вещественной переменной x, равное 1.5. Для этого наберем следующую команду:
x = parse(Float64, readline())
С ее помощью будет выполняться ввод с клавиатуры значения переменной x и преобразование ее в вещественный тип.
Затем в появившемся поле введите число 1.5 и нажмите клавишу Enter.
Следующей командой возведите в квадрат переменную x.
x = parse(Float64, readline())
x^2
x = parse(Float64, readline())
stdin> 1.5
1.5
x^2
2.25
Чтение и запись файлов
Работа с текстовыми файлами
Язык Julia предоставляет возможности для чтения данных из файла и для записи в файл.
Чтобы начать работу с файлом, сначала его необходимо открыть. Для этого используется функция open(filename), где filename – имя физического файла в локальном окружении Engee, взятое в двойные кавычки. Значение функции open присваивается переменной типа IOStream (поток ввода-вывода).
Для чтения всех строк из текстового файла используется функция readlines, для чтения одной строки – функция readline. Аргументом этих функций служит переменная типа IOStream.
Пример. Прочитаем все строки из файла data.txt и присвоим их переменной x:
x = readlines("/user/Курс_«Основы_программирования_в_Engee»/Курс «Основы программирования в Engee»/data.txt")
Этот файл содержит три строки. Они считываются в вектор x, состоящий из элементов строкового типа. Каждый элемент вектора представляет собой отдельную строку текста.
Пример. Прочитаем одну строку из файла data.txt:
x = readline("/user/Курс_«Основы_программирования_в_Engee»/Курс «Основы программирования в Engee»/data.txt")
В приведенных выше примерах функция open открывала файл, расположенный в текущей папке (в той же папке, в которой находится данный интерактивный этот скрипт). Если вы хотите открыть файл, расположенный в другой папке, то в качестве аргумента функции нужно написать полный путь к файлу вместе с его именем. Например, к тому же самому файлу data.txt можно обратиться с использованием полного пути:
f = open("/user/start/Курсы/Курс «Основы программирования в Engee»/data.txt")
Обратите внимание на то, что в локальном окружении Engee корневая папка называется /user, а учебные курсы расположены в папках /user/start/Курсы/Название курса.
Julia позволяет сменить текущую папку с помощью команды cd. Например:
cd("/user/start/Курсы/Курс «Основы программирования в Engee»")
После этого можно обращаться к файлам из этой папки только по имени, без указания пути:
f = open("data.txt")
Для того чтобы открыть файл для записи данных, используется функция open(filename, "w"), где второй агрумент w указывает на то, что файл открывается в режиме создания. При этом будет создан новый файл с именем filename.
Пример. Создадим и откроем для записи файл my_file.txt.
f = open("my_file.txt","w")
После выполнения этой строки кода во вкладке Файлы вы увидите новый файл my_file.txt.
В таблице перечислены возможные режимы открытия файлов:
| Режим | Описание |
|---|---|
| r | чтение |
| w | чтение, создание, обрезка |
| a | чтение, создание, присоединение |
| r+ | чтение, запись |
| w+ | чтение, запись, создание, обрезка |
| a+ | чтение, запись, создание, присоединение |
Для записи данных в файл используется функция write.
Пример. Запишем в файл строку This is my text. Для перехода на новую строку в конце строковой константы добавлено \n.
write(f, "This is my text\n")
Добавим в файл вторую строку с текстом This is another text.
write(f, "This is another text\n")
Если нужно записать в файл числовые данные, то их нужно преобразовать в строковый тип с помощью функции string.
write(f, string(8734.354))
Если вы просмотрите содержимое файла my_file.txt на этом этапе, то вы увидите, что файл пустой. Для того чтобы данные фактически записались, файл должен быть закрыт. Файл закрывается с помощью функции close:
close(f)
После выполнения этой команды файл будет содержать три строки с данными.
Для удаления файла используется функция rm(filename).
Пример. Удалим созданный нами файл my_file.txt:
rm("my_file.txt")
Работа с числовыми файлами
Для работы с числовыми данными, оформленными в виде таблиц, широко используются файлы в формате csv. Для доступа к функциям, позволяющим работать с табличными данными, необходимо подключить библиотеки CSV и DataFrames. Функция CSV.read(filename, DataFrame) позволяет прочитать данные из файла в переменную табличного типа DataFrame.
Пример. Прочитаем данные из файла data_table.csv:
using CSV, DataFrames
data = CSV.read("data_table.csv", DataFrame)
Мы видим, что каждый столбец таблицы имеет свое имя: Jan, Feb, Mar и Apr. Извлечь столбец из таблицы DataFrame можно при помощи обращения через точку: таблица.Имя_Переменной. Например, так:
x = data.Jan
y = data.Feb
Если нужно получить не весь столбец, а некоторые его элементы, то можно воспользоваться такой конструкцией:
z = data[1, "Mar"]
Здесь переменной z присваивается значение первого элемента в столбце Mar таблицы data.
Если нужно получить несколько элементов, идущих подряд в каком-либо столбце, то первый индекс записывается в виде диапазона: начало:конец. Например, присвоим переменной t элементы со 2-го по 4-й в столбце Apr таблицы data:
t = data[2:4, "Apr"]
Больше о работе с данными в Julia с помощью библиотеки DataFrames можно прочитать в документации.
Работа с графическими файлами
Для работы с графическими файлами необходимо подключить библиотеки Images и ImageShow. Открыть файл с изображением можно с помощью функции load(filename), а просмотреть изображение – с помощью функции simshow.
Пример. Откроем и просмотрим графический файл image.jpg:
using Images, ImageShow
A = load("image.jpg")
simshow(A)
Больше о функциях ввода/вывода и работы с файлами в Julia вы можете прочитать в документации.
Массивы
Массив – это коллекция объектов, хранящихся в многомерной таблице.
Одномерные массивы
В зависимости от способа создания одномерный массив в Julia может иметь тип Vector (вектор) или Matrix (матрица).
Вектор задается перечислением его элементов через запятую или точку с запятой в квадратных скобках. Например:
a = [1, 2, 3, 4, 5]
или
a = [1; 2; 3; 4; 5]
Элементами массивов могут быть не только целые числа, как в приведенных примерах, но и элементы любого другого типа (вещественные, комплексные, рациональные, логические, символьные, строковые и т.д.). Они также могут быть результатами вычисления каких-либо математических или логических выражений.
Матрица-строка создается с помощью перечисления ее элементов через пробел в квадратных скобках. Например:
a = [1 2 3 4 5]
Двумерные массивы
Двумерные массивы имеют несколько строк и столбцов. Ввод элементов осуществляется по строкам, элементы одной строки отделяются друг от друга пробелами, а строки отделяются точкой с запятой. Все двумерные массивы в Julia имеют тип Matrix.
Например, зададим двумерный массив, содержащий 3 строки и 5 столбцов:
a = [1 2 3 4 5; 6 7 8 9 10; 11 12 13 14 15]
Задание арифметических последовательностей
Оператор :
Часто бывает нужно создать вектор или матрицу, содержащие упорядоченные последовательности чисел. Упорядоченная последовательность создается с помощью оператора : для определения диапазона, заданного своими границами: начало:конец. Шаг между числами по умолчанию равен 1.
Например, выражение 2:5 задает диапазон целых чисел от 2 до 5 с шагом 1, т.е. 2, 3, 4, 5.
Однако, если мы введем команду x = 2:5 или x = [2:5], то у нас получится не вектор, а объект типа диапазон (range). Он будет хранить не сами элементы диапазона, а их функцию-генератор:
x = [2:5]
Если после диапазона добавить точку с запятой (;), то мы получим объект типа Vector:
x = [2:5;]
Оператор диапазона позволяет задавать числа с произвольным шагом с помощью такой конструкции:
начало:шаг:конец.
С помощью оператора диапазона зададим вектор целых чисел от 10 до 20 с шагом 2:
x = [10:2:20;]
Функция collect
Еще один способ преобразовать диапазон в вектор – использование функции collect.
Например, диапазон целых чисел от 1 до 10 с шагом 1 может быть преобразован в объект типа Vector следующим образом:
collect(1:10)
Функция LinRange
Если известно количество элементов, из которого должен состоять вектор, то задать диапазон равномерно распределенных чисел можно при помощи функции LinRange:
LinRange(начало, конец, количество_элементов)
Здесь для разделения аргументов команды используются запятые (,).
Зададим диапазон от 0 до 10, сотстоящий из 5 чисел:
x = LinRange(0, 10, 5)
В результате получается объект типа LinRange. Чтобы преобразовать его в тип Vector, воспользуемся знакомой нам функцией collect:
collect(x)
Задавая векторы в Julia, мы всегда получаем векторы-стобцы. Если нам необходимо получить вектор-строку, то можно воспользоваться операцией трнспонирования (').
Пример:
x = [1:5;]
x'
Заметим, что вектор стал не матрицей, а объектом типа adjoint. Обычно это не создает проблем при вычислениях.
Операции с массивами
Чтобы к каждому элементу массива прибавить одно и то же число, нужно использовать оператор сложения с точкой (.+). Например:
x = [1 2 3]
y = x .+ 4
Аналогично выполняется вычитание одного и того же числа из каждого элемента массива. Например:
y = x .- 5
Если нужно умножить или разделить все элементы массива на скаляр, то можно воспользоваться обычным синтаксисом:
y = x*2
y = x / 10
Чтобы сложить два массива одинаковой длины, синтаксис для поэлементного сложения .+ тоже сработает, но проще сложить векторы обычным образом, с помощью оператора +. То же самое относится и к вычитанию массивов.
z = x + y
w = x - y
В Julia большинство функций можно применить к массивам, используя поэлементную нотацию (с точкой после имени функции).
Например, квадратный корень из каждого элемента массива x вычисляется так:
x = [1 2 3]
sqrt.(x)
Оператор * осуществляет матричное умножение. Для этого число столбцов в первой матрице должно быть равно числу строк во второй. В противном случае матричное умножение будет невозможным.
Пример. Умножим матрицу на вектор-столбец .
A = [1 2; 3 4]
B = [5; 6]
A * B
С помщью оператора .* можно выполнить поэлементное умножение массивов одинакового размера. Например:
A = [1 2]
B = [3 4]
A .* B
Индексация элементов массивов
Получить значение какого-либо элемента одномерного массива можно, обращаясь к его индексу в квадратных скобках. Нумерация элементов в Julia начинается с единицы.
Пример. Зададим вектор x и вызовем его третий и пятый элементы:
x = [238 435 546 659 412 3456 562 534 433 234]
a = x[3]
b = x[5]
Чтобы получить первый элемент массива, можно использовать как индекс 1, так и ключевое слово begin.
Пример. Вызовем первый элемент массива x:
c = x[begin]
Чтобы получить последний элемент массива, можно использовать ключевое слово end.
Пример. Вызовем последний и предпоследний элементы массива x:
d = x[end]
h = x[end-1]
Для вызова элемента двумерного массива A используются два индекса через запятую: A[i,j]. Первый индекс i означает номер строки, второй индекс j – номер столбца, на пересечении которых находится этот элемент.
Пример. Зададим матрицу A и присвоим переменной a значение элемента, находящегося во 2-й строке и 3-м столбце матрицы A:
A = [1 2 3; 4 5 6; 7 8 9]
a = A[2,3]
Можно изменить значения выбранных элементов массива, присвоив им новые значения.
Пример. Присвоим элементу A[1,1] значение 100 и выведем на экран обновленную матрицу A:
A[1,1] = 100
display(A)
Можно индексировать элементы матриц при помощи одномерного индекса. Тогда Julia использует такой порядок индексации: счетчик элементов будет последовательно отсчитывать их вдоль столбцов, начиная с первго, пока не дойдет до элемента с заданным индексом. Например, следующий код вернет значение 6.
A = [5 6;
7 8]
A[3]
Оператор двоеточие (:) можно использовать в качестве индекса массива. Тогда он будет обозначать, что нужно вернуть все элементы по некоторой размерности массива. Например, следующий код создаст вектор-столбец, в котором содержатся все элементы из первого столбца матрицы A.
A = [1 2 3; 4 5 6; 7 8 9]
x = A[:, 1]
Оператор : можно использовать для задания диапазона индексов. Вот, например, код, который возвращает матрицу, состоящую из первой, второй и третьей строк некоторой матрицы B.
B = [1 2 3; 4 5 6; 7 8 9; 10 11 12; 13 14 15]
x = B[1:3,:]
Индексацию не обязательно производить при помощи непрерывных рядов. Например, следующий код извлекает первый, третий и шестой элементы вектора x. При этом в качестве индекса передается список [1 3 6].
x = [100:110;]
x[[1 3 6]]
Функции для работы с массивами
Общие функции
eltype(A)– тип элементов в массивеA;length(A)– количество элементов в массивеA;ndims(A)– количество измерений массиваA;size(A)– кортеж, содержащий размеры массиваAпо всем измерениям;size(A,n)– кортеж, содержащий размер массиваAпо измерениюn.
Пример. Создадим двумерный массив и определим тип и количество элементов в нем, количество измерений и его размеры по всем измерениям.
A = [1 2 3 4 5; 6 7 8 9 10; 11 12 13 14 15]
eltype(A)
length(A)
ndims(A)
size(A)
В Julia доступно множество функций для создания и инициализации массивов. В приведенном ниже списке вызовы с аргументом dims... могут принимать либо один кортеж с размерами измерений, либо набор размеров измерений, передаваемый в виде переменного числа аргументов. Большинство таких функций также принимают первый аргумент T, определяющий тип элементов массива. Если аргумент T не указан, по умолчанию используется тип Float64.
zeros(T, dims...)– массив размеромdimsсо всеми элементами, равными нулю;ones(T, dims...)– массив размеромdimsсо всеми элементами, равными 1;trues(dims...)– массив размеромdimsсо всеми элементами, равнымиtrue;falses(dims...)– массив размеромdimsсо всеми элементами, равнымиfalse;copy(A)– копирует массивA;reinterpret(T, A)– массив с теми же двоичными данными, что и вA, но с типом элементовT;rand(T, dims...)– массив размеромdimsсо случайными, независимо, одинаково и равномерно распределенными значениями. Для типов с плавающей запятойTзначения находятся в интервале ;randn(T, dims...)– массив размеромdimsсо случайными, независимо и одинаково распределенными значениями, имеющими стандартное нормальное распределение (с математическим ожиданием, равным нулю, и со средним квадратическим отклонением, равным 1);Matrix{T}(I, m, n)– матрица, у которой на главной диагонали находятся единицы, а остальные элементы – нули (матрицы тождественности) размером . ДляIтребуется подключение библиотекиLinerarAlgebra;range(start, stop, n)– диапазон изnэлементов, распределенных с равным шагом отstartдоstop;fill(x, dims...)– заполняет массив размеромdimsзначениямиx.
Примеры. Создадим двумерный массив размером , заполненный нулями. Ниже показаны три способа записи соответствующей команды.
A = zeros(Int8, 4, 5)
A = zeros(Int8, (4, 5))
A = zeros(4, 5)
Создадим массив размером с равномерно распределенными случайными числами в интервале :
A = rand(3, 3)
Создадим единичную матрицу размером :
using LinearAlgebra
A = Matrix{Int8}(I, 7, 7)
Заполним массив размером числами 5:
fill(5, (3,4))
Изменение размеров массива
reshape(A, dims...)– массив с теми же данными, что и вA, но с другими измерениями;transpose(A)– транспонирование массиваA;cat(A..., dims)– выполняет конкатенацию (объединение) входных массивов в измерениях, указанных вdims. Еслиdims=1, то этоvcat; еслиdims=2, тоhcat;vcat(A...)– выполняет конкатенацию массивов или чисел по вертикали. Эквивалентнаcat(A...; dims=1);hcat(A...)– выполняет конкатенацию массивов или чисел по горизонтали. Эквивалентнаcat(A...; dims=2);
Пример. Зададим одномерный массив размером из 16 элементов и с помощью функции reshape изменим его размер так, чтобы он стал двумерным и содержал 2 строки и 8 столбцов.
x = [1:16;]
reshape(x, 2, 8)
Функции для работы с элементами массива
in(x, A)илиx in A– проверяет, находится ли элементxв массивеA.
A = [3 4 1 5 2]
in(3, A)
7 in A
maximum(A)– находит максимальный элемент массиваA.
maximum(A)
minimum(A)– находит минимальный элемент массиваA.
minimum(A)
sum(A)– суммирование элементов массиваA.
sum(A)
sum(A, dims=n)– суммирование элементов двумерного массиваAпо столбцам (еслиdims=1) или по строкам (еслиdims=2).
A = [1 2 3; 4 5 6; 7 8 9]
sum(A, dims=1)
sum(A, dims=2)
- Элементы массива можно заполнить с помощью функциональной зависимости по следующей схеме:
A = [выражение for индекс in начало:шаг:конец]
Переменная индекс пробегает все значения в диапазоне от начало до конец с заданным шагом (если шаг равен 1, то его можно не писать). Значения элементов массива определяются с помощью выражения, которое, в частности, может зависеть от переменной индекс.
Например, зададим одномерный массив с десятью элементами, заполненный квадратами натуральных чисел от 1 до 10.
A = [i^2 for i in 1:10]
Таким же способом можно задавать двумерные массивы. Например, заполним двумерный масссив произведениями чисел x*y, если x изменятется от 1 до 5, а y – от 6 до 9.
A = [x*y for x = 1:5, y = 6:9]
sort(A, dims=n)– производит сортировку элементов массиваAпо указанной размерности в порядке возрастания.sort(A, dims=n, rev=true)– производит сортировку элементов массиваAпо указанной размерности в порядке убывания.
Для одномерного веткора-строки нужно указывать dims=2. Ниже приведены примеры сортировки элементов одномерного массива:
x = [7 4 1 9 6 0 5 8 3 2]
sort(x, dims=2)
sort(x, dims=2, rev=true)
Аналогичная функция sort! (с восклицательным знаком) записывает результат в векторx.
Символы и строки
Символы
Встроенным типом, используемым для символов в Julia, является тип Char. Значение типа Char представляет собой один символ. Это 32-разрядный примитивный тип, который может быть преобразован в числовое значение, представляющее код символа Unicode. Значения типа Char вводятся и отображаются в одинарных кавычках:
c = 'x'
Переменные и константы типа Char с помощью функции Int можно преобразовать в целочисленное значение, т.е. в код символа:
c = Int('x')
typeof(c)
Целочисленное значение с помощью функции Char можно преобразовать обратно в символьный тип:
Char(120)
Вы можете выполнять сравнения и арифметические действия со значениями типа Char (на самом деле все действия выполняются с кодами этих символов):
'A' < 'a'
'A' <= 'a' <= 'Z'
'x' - 'y'
'A' + 1
Не все целочисленные значения являются допустимыми кодами символов Unicode, но для повышения производительности преобразование типа Char не проверяет допустимость каждого символьного значения. Чтобы проверить тот факт, что каждое преобразованное значение является допустимым кодом символа, используйте функцию isvalid. Например:
Char(0x110000)
isvalid(Char, 0x110000)
Допустимыми кодами символов Unicode являются U+0000--U+D7FF и U+E000--U+10FFFF. Еще не всем им присвоены понятные значения, и они не обязательно интерпретируются приложениями, но все эти значения считаются допустимыми символами Unicode.
Вы можете ввести любой символ Unicode в одинарных кавычках, используя символ \u, за которым следует до четырех шестнадцатеричных цифр, или символ \U, за которым следует до восьми шестнадцатеричных цифр (для самого длинного допустимого значения требуется только шесть цифр).
'\u78'
'\u2200'
'\U10ffff'
Строки
Строки – это конечные последовательности символов.
Есть несколько примечательных особенностей, касающихся строк Julia.
-
Встроенным типом, используемым для строк в Julia, является тип
String. Он поддерживает полный набор символов Unicode через кодировку UTF-8. Для преобразования в другие кодировки Unicode и из них существует функцияtranscode. -
Cтроки являются неизменяемыми: значение объекта
Stringне может быть изменено. Чтобы создать другое строковое значение, нужно построить новую строку из частей других строк.
Строковые значения вводятся в двойных кавычках или в тройных двойных кавычках. Отображаются они всегда в двойных кавычках.
s = "Hello, world."
s = """Выражение "в кавычках" внутри строки"""
Длинные строки можно разбить на несколько строк, предваряя новую строку обратным слешем (\).
s = "This is a long \
line"
Чтобы извлечь символ из строки, к нему нужно обратиться по индексу, как к элементу одномерного массива.
Например, извлечем первый элемент из заданной ранее строки s:
s[begin]
Шестой элемент:
s[6]
Последний элемент:
s[end]
Индекс первого элемента (первый символ строки) возвращается функцией firstindex(s), а индекс последнего элемента (символа) – функцией lastindex(s). Ключевые слова begin и end могут использоваться внутри операции индексирования как сокращение для первого и последнего индексов соответственно в заданном измерении. Индексирование строк, как и большинство индексирований в Julia, начинается с 1. Функция firstindex всегда возвращает 1 для любого объекта типа String. Однако функция lastindex(s) обычно не то же самое, что функция length(s) для строки, поскольку некоторые символы Unicode могут занимать несколько единиц кода.
Чтобы извлечь подстроку, используется индексирование диапазона (оператор :):
s = "This is a long \
line"
s[11:14]
Обратите внимание, что выражения s[k] и s[k:k] не дают одинакового результата.
s[4]
s[4:4]
В первом случае получается символьное значение типа Char, а во втором случае – строковое значение типа String, которое содержит только один символ. В Julia это совершенно разные вещи.
Для создания копии выбранной части исходной строки можно воспользоваться функцией SubString. Например:
str = "long string"
substr1 = SubString(str, 1, 4)
substr2 = SubString(str, 6, 11)
Операции со строками
Конкатенация
Одной из самых распространенных и полезных операций со строками является конкатенация.
Пример. Зададим две строковые переменные и объединим их с помощью функции string:
h = "Hello"
w = "world"
str = string(h, ", ", w, ".")
Другой способ конкатенации – использование оператора * вместо функции string.
str = h * ", " * w * "."
Еще один способ объедиения строк – интерполяция. Для этого объединяемые строки записываются подряд в общих двойных кавычках, а перед именами строковых перменных ставится символ $:
str = "$h, $w."
С помощью символа $ \text{можно} \text{преобразовать} \text{в} \text{строку} \text{результаты} \text{математических} \text{выражений}. \text{Например}, \text{результат} \text{вычисления} \text{выражения} преобразуется в строковый тип следующим образом:
s = "$(4pi^2)"
Это более удобочитаемая и целесообразная возможность, эквивалентная приведенной выше конкатенации строк. Система переписывает это выражение в вызов string(h, ", ", w, ".").
Чтобы включить символ $ в строку, экранируйте его обратным слешем:
print("I have \$100 in my account.")
Сравнение строк
Вы можете сравнивать строки, используя стандартные операторы сравнения.
"one" < "two"
"one" == "two"
"Hello" != "Goodbye"
Поиск символа в строке
Вы можете искать индекс первого символа в строке с помощью функции findfirst и индекс последнего символа с помощью функции findlast:
findfirst('g', "programming")
findlast('g', "programming")
findfirst('b', "programming")
В третьем примере, при отсутствии в строке заданного символа, функция findfirst не выдала никакого результата.
Вы можете начать поиск символа с заданного смещения с помощью функций findnext и findprev.
findnext('o', "xylophone", 1)
findnext('o', "xylophone", 5)
findprev('o', "xylophone", 5)
findnext('o', "xylophone", 8)
Поиск подстроки в строке
Вы можете использовать функцию occursin(substr, str), чтобы проверить, содержится ли подстрока substr в строке str.
occursin("world", "Hello, world.")
occursin("o", "Julia")
Другие функции
Далее перечислены некоторые другие полезные функции для работы со строками.
-
length(str)возвращает количество символов в строке (str). -
length(str, i, j)возвращает количество допустимых индексов символов в строке (str) отiдоj. -
thisind(str, i)при заданном произвольном индексе в строке находит первый индекс символа, на который указывает индекс. -
nextind(str, i, n=1)находит начало n-го символа, начинающегося после индекса (i). -
prevind(str, i, n=1)находит начало n-го символа, начинающегося перед индексом (i).